//-------------------------------------------------------------------------------------------------
// Copyright (c) Bradford W. Mott and Flare Contributors
// North Carolina State University, Department of Computer Science
// The IntelliMedia Group
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
// OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//-------------------------------------------------------------------------------------------------

using System;
using System.Text;

namespace Flare
{
    [FlagsAttribute]
    public enum Subsystem
    {
        None                = 0x0000,
        LoadingGeneral      = 0x0001,
        Playback            = 0x0002,
        All                 = 0xffff
    }

    public static class Log
    {
        static string LogPrefix = typeof(Log).Namespace;

#if (SILVERLIGHT || WPF)
        class Trace
        {
            internal static void Write(string msg)
            {
                System.Diagnostics.Debug.WriteLine(msg);
            }

            internal static void WriteLine(string msg)
            {
                Write(msg);
            }

            internal static void TraceError(string msg)
            {
                Write("ERROR: " + msg);
            }

            internal static void TraceWarning(string msg)
            {
                Write("WARNING: " + msg);
            }
        }
#else
        class Trace
        {
            internal static void Write(string msg)
            {
                UnityEngine.Debug.Log(msg);
            }

            internal static void WriteLine(string msg)
            {
                UnityEngine.Debug.Log(msg);
            }

            internal static void TraceError(string msg)
            {
                UnityEngine.Debug.LogError(msg);
            }

            internal static void TraceWarning(string msg)
            {
               UnityEngine.Debug.LogWarning(msg);
            }
        }
#endif
        static Log()
        {
            SubsystemFilter = Subsystem.All;
            AlwaysLogErrors = false;
            AlwaysLogWarnings = false;
        }

        public static bool AlwaysLogErrors { get; set; }
        public static bool AlwaysLogWarnings { get; set; }

        public static string SafeValue(object value)
        {
            return (value != null ? value.ToString() : "null");
        }

        public static Subsystem SubsystemFilter { get; set; }

        public static void Write(Subsystem subsystem, string format, params object[] args)
        {
            if ((SubsystemFilter & subsystem) != 0)
            {
                Trace.Write(string.Format("[{0}:{1}] {2}",
                    LogPrefix,
                    subsystem.ToString(),
                    string.Format(format, args)));
            }
        }

        public static void WriteLine(Subsystem subsystem, string format, params object[] args)
        {
            if ((SubsystemFilter & subsystem) != 0)
            {
                Trace.WriteLine(string.Format("[{0}:{1}] {2}",
                    LogPrefix,
                    subsystem.ToString(),
                    string.Format(format, args)));
            }
        }

        public static void Error(Subsystem subsystem, string format, params object[] args)
        {
            Error(subsystem, null, format, args);
        }

        public static void Error(Subsystem subsystem, Exception e)
        {
            Error(subsystem, e, null);
        }

        public static void Error(Subsystem subsystem, Exception e, string format, params object[] args)
        {
            WriteLine(true, subsystem, e, format, args);
        }

        public static void Warning(Subsystem subsystem, string format, params object[] args)
        {
            Warning(subsystem, null, format, args);
        }

        public static void Warning(Subsystem subsystem, Exception e)
        {
            Warning(subsystem, e, null);
        }

        public static void Warning(Subsystem subsystem, Exception e, string format, params object[] args)
        {
            WriteLine(false, subsystem, e, format, args);
        }

        private static void WriteLine(bool error, Subsystem subsystem, Exception e, string format, params object[] args)
        {
            if (((error && !AlwaysLogErrors)
                || (!error && !AlwaysLogWarnings))
                && (SubsystemFilter & subsystem) == 0)
            {
                // Skip logging due to filter
                return;
            }

            StringBuilder msg = new StringBuilder();
            msg.AppendFormat("[{0}:{1}] ",
                        LogPrefix,
                        subsystem.ToString());
            if (format != null)
            {
                msg.AppendFormat(format, args);
                msg.AppendLine();
            }

            int innerExceptionIndex = 0;
            Exception ex = e;
            while (ex != null)
            {
                msg.AppendFormat("   Exception [{0}]: {1}\n{2}\n\n",
                    innerExceptionIndex++,
                    ex.Message,
                    ex.StackTrace);

                ex = ex.InnerException;
            }

            if (error)
            {
                WriteError(msg.ToString());
            }
            else
            {
                WriteWarning(msg.ToString());
            }
        }

        public static void WriteError(string format, params object[] args)
        {
            Trace.TraceError(string.Format(format, args));
        }

        public static void WriteWarning(string format, params object[] args)
        {
            Trace.TraceWarning(string.Format(format, args));
        }
    }
}
